auto.waitFor();
console.show(true);
importClass(org.opencv.imgproc.Imgproc);
importClass(org.opencv.core.Core);
importClass(org.opencv.core.Rect);
importClass(org.opencv.core.Mat);
importClass(org.opencv.core.Point);
importClass(org.opencv.core.Size);
importClass(org.opencv.core.CvType);
importClass(org.opencv.core.Scalar);
importClass(org.opencv.imgcodecs.Imgcodecs);
function real_click_with_case(input) {
    let x, y, centerX, centerY, offsetX, offsetY, randomX, randomY;

    // 处理输入是一个坐标对象的情况
    if (input && typeof input === 'object' && 'x' in input && 'y' in input) {
        x = input.x;
        y = input.y;

        // 尝试点击 3 次，若点击失败则随机偏移
        for (let i = 1; i <= 3; i++) {
            if (click(x, y)) {
                log("real click: true");
                return true;
            }
            let randomSleepTime = Math.floor(Math.random() * (500 - 100 + 1)) + 100;
            sleep(randomSleepTime);
        }

        // 偏移量
        offsetX = Math.floor(Math.random() * 21) - 10;
        offsetY = Math.floor(Math.random() * 21) - 10;
        randomX = x + offsetX;
        randomY = y + offsetY;

        click(randomX, randomY);
        return false;
    }

    // 处理输入是一个包含 click 方法的对象的情况
    else if (input && typeof input === 'object' && typeof input.click === 'function') {
        for (let i = 1; i <= 3; i++) {
            if (input.click()) {
                log("real click: true");
                return true;
            }
            let randomSleepTime = Math.floor(Math.random() * (500 - 100 + 1)) + 100;
            sleep(randomSleepTime);
        }

        // 偏移量基于该对象的中心坐标
        centerX = input.bounds().centerX();
        centerY = input.bounds().centerY();
        offsetX = Math.floor(Math.random() * 7) - 3;
        offsetY = Math.floor(Math.random() * 7) - 3;
        randomX = centerX + offsetX;
        randomY = centerY + offsetY;

        click(randomX, randomY);
        return false;
    }

    // 如果输入类型不符合要求，输出错误信息
    log("Invalid input type.");
    return false;
}
function clickimage(obj) {
    let x, y, centerX, centerY, offsetX, offsetY, randomX, randomY;
    centerX = obj.bounds().centerX();
    centerY = obj.bounds().centerY();
    offsetX = Math.floor(Math.random() * 7) - 3;
    offsetY = Math.floor(Math.random() * 7) - 3;
    randomX = centerX + offsetX;
    randomY = centerY + offsetY;
    click(randomX, randomY);
}
/*
-------
*/
//从接口获取数据
function getdata() {
    http.__okhttp__.setTimeout(1000);
    let url = 'http://116.62.222.143:3000/api/gettask';
    for (var i = 0; i < 10; i++) {
        try {
            let res = http.get(url, {
                timeout: 10000 // 设置超时时间为10秒
            });
            // console.log(res.statusCode);
            if (res.statusCode == 200) {
                var data = res.body.string();
                //log(UI);
                return JSON.parse(data);
            } else {
                toastLog('接口：' + '下载失败');
            }
        } catch (error) {
            if (error instanceof java.net.SocketTimeoutException) {
                toastLog('接口:' + '请求超时');
                continue;
            } else {
                toastLog('接口' + '请求失败')//，错误：' + error);
            }
        }
        if (i == 9) {
            i = 0;
        }
        sleep(1111);
    }
    // log(UI);//
}
//从接口获取数据
/*
-------
*/
//哔站跳转
function bilibilijump(liveid) {
    app.startActivity({
        action: "android.intent.action.VIEW",
        data: "bilibili://live/" + liveid,
        packageName: "tv.danmaku.bili",
    });
}
//哔站跳转
/*
-------
*/
//
function liveroomyesornot() {
    id("tv.danmaku.bili:id/rank_sum_tv").waitFor();//直播间标志：在线人数
    var jsq1 = 0;
    while (true) {
        var target = id("tv.danmaku.bili:id/pager").find();
        // log(target.length);
        sleep(3333);
        if (target) {
            log("已进入直播间");
            return true;
        }
        jsq1++;
        if (jsq1 > 3) {
            return false;
        }
    };
}
/*
-------
*/
//避免重复直播间
var repeat = [];
function avoidrepeat(obj) {
    if (repeat.length == 0) {
        log("未重复，继续");
        return true;
    } else {
        for (q = 0; q < repeat.length; q++) {
            if (obj.roomid == repeat[q].roomid && obj.time < repeat[q].time) {
                repeat[q].time = obj.time;
                log("重复跳过");
                return false;
            } else {
                log("未重复，继续");
                return true;
            };
        };
    }
}
//避免重复直播间
/*
-------
*/
//全分辨率找图
/**
 * @param {number[]} region 是一个两个或四个元素的数组。
 * (region[0], region[1])表示找色区域的左上角；region[2]*region[3]表示找色区域的宽高。如果只有region只有两个元素，则找色区域为(region[0], region[1])到屏幕右下角。
 * 如果不指定region选项，则找色区域为整张图片。
 * @param {*} img
 * @returns {org.opencv.core.Rect}
 */
function buildRegion(region, img) {
    if (region == undefined) {
        region = [];
    }
    let x = region[0] === undefined ? 0 : region[0];
    let y = region[1] === undefined ? 0 : region[1];
    let width = region[2] === undefined ? img.getWidth() - x : region[2];
    let height = region[3] === undefined ? img.getHeight() - y : region[3];
    if (x < 0 || y < 0 || x + width > img.width || y + height > img.height) {
        throw new Error(
            'out of region: region = [' + [x, y, width, height] + '], image.size = [' + [img.width, img.height] + ']'
        );
    }
    return new Rect(x, y, width, height);
}
/**
 * @param {number} threshold 图片相似度。取值范围为0~1的浮点数。默认值为0.9
 * @param {number[]} region 找图区域
 * @param {number[]} scaleFactors 大图的宽高缩放因子，默认为 [1, 0.9, 1.1, 0.8, 1.2]
 * @param {number} max 找图结果最大数量，默认为5
 * @param {boolean} grayTransform 是否进行灰度化预处理，默认为true。
 * 通常情况下将图像转换为灰度图可以简化匹配过程并提高匹配的准确性，当然，如果你的匹配任务中颜色信息对匹配结果具有重要意义，
 * 可以跳过灰度化步骤，直接在彩色图像上进行模板匹配。
 */
function MatchOptions(threshold, region, scaleFactors, max, grayTransform) {
    this.threshold = threshold;
    this.region = region;
    this.scaleFactors = scaleFactors;
    this.max = max;
    this.grayTransform = grayTransform;
}
const defaultMatchOptions = new MatchOptions(
    0.9,
    undefined,
    [
        [1, 1],
        [0.9, 0.9],
        [1.1, 1.1],
        [0.8, 0.8],
        [1.2, 1.2],
        [32 / 9, 0.9],

    ],
    6,
    true
);
// 校验参数
MatchOptions.check = function (options) {
    if (options == undefined) {
        return defaultMatchOptions;
    }
    // deep copy
    let newOptions = JSON.parse(JSON.stringify(options));
    if (newOptions.threshold == undefined) {
        newOptions.threshold = defaultMatchOptions.threshold;
    }
    if (newOptions.region && !Array.isArray(newOptions.region)) {
        throw new TypeError('region type is number[]');
    }
    if (newOptions.max == undefined) {
        newOptions.max = defaultMatchOptions.max;
    }
    if (newOptions.scaleFactors == undefined) {
        newOptions.scaleFactors = defaultMatchOptions.scaleFactors;
    } else if (!Array.isArray(newOptions.scaleFactors)) {
        throw new TypeError('scaleFactors');
    }
    for (let index = 0; index < newOptions.scaleFactors.length; index++) {
        let factor = newOptions.scaleFactors[index];
        if (Array.isArray(factor) && factor[0] > 0 && factor[1] > 0) {
            // nothing
        } else if (typeof factor === 'number') {
            newOptions.scaleFactors[index] = [factor, factor];
        } else {
            throw new TypeError('scaleFactors');
        }
    }
    if (newOptions.grayTransform === undefined) {
        newOptions.grayTransform = defaultMatchOptions.grayTransform;
    }

    return newOptions;
};

function Match(point, similarity, scaleX, scaleY) {
    this.point = point;
    this.similarity = similarity;
    this.scaleX = scaleX;
    this.scaleY = scaleY;
}

/**
 * 找图，在图中找出所有匹配的位置
 * @param {Image} img
 * @param {Image} template
 * @param {MatchOptions} options 参数见上方定义
 * @returns {Match[]}
 */
function matchTemplate(img, template, options) {
    if (img == null || template == null) {
        throw new Error('ParamError');
    }
    options = MatchOptions.check(options);
    console.log('参数：', options);

    let largeMat = img.mat;
    let templateMat = template.mat;
    let largeGrayMat;
    let templateGrayMat;
    if (options.region) {
        options.region = buildRegion(options.region, img);
        largeMat = new Mat(largeMat, options.region);
    }
    // 灰度处理
    if (options.grayTransform) {
        largeGrayMat = new Mat();
        Imgproc.cvtColor(largeMat, largeGrayMat, Imgproc.COLOR_BGR2GRAY);
        templateGrayMat = new Mat();
        Imgproc.cvtColor(templateMat, templateGrayMat, Imgproc.COLOR_BGR2GRAY);
    }
    // =================================================
    let finalMatches = [];
    for (let factor of options.scaleFactors) {
        let [fx, fy] = factor;
        let resizedTemplate = new Mat();
        Imgproc.resize(templateGrayMat || templateMat, resizedTemplate, new Size(), fx, fy, Imgproc.INTER_LINEAR);
        // 执行模板匹配，标准化相关性系数匹配法
        let matchMat = new Mat();
        Imgproc.matchTemplate(largeGrayMat || largeMat, resizedTemplate, matchMat, Imgproc.TM_CCOEFF_NORMED);

        let currentMatches = _getAllMatch(matchMat, resizedTemplate, options.threshold, factor, options.region);
        console.log('缩放比：', factor, '可疑目标数：', currentMatches.length);
        for (let match of currentMatches) {
            if (finalMatches.length === 0) {
                finalMatches = currentMatches.slice(0, options.max);
                break;
            }
            if (!isOverlapping(finalMatches, match)) {
                finalMatches.push(match);
            }
            if (finalMatches.length >= options.max) {
                break;
            }
        }
        resizedTemplate.release();
        matchMat.release();
        if (finalMatches.length >= options.max) {
            break;
        }
    }
    largeMat !== img.mat && largeMat.release();
    largeGrayMat && largeGrayMat.release();
    templateGrayMat && templateGrayMat.release();

    return finalMatches;
}

function _getAllMatch(tmResult, templateMat, threshold, factor, rect) {
    let currentMatches = [];
    let mmr = Core.minMaxLoc(tmResult);

    while (mmr.maxVal >= threshold) {
        // 每次取匹配结果中的最大值和位置，从而使结果按相似度指标从高到低排序
        let pos = mmr.maxLoc; // Point
        let value = mmr.maxVal;

        let start = new Point(Math.max(0, pos.x - templateMat.width() / 2), Math.max(0, pos.y - templateMat.height() / 2));
        let end = new Point(
            Math.min(tmResult.width() - 1, pos.x + templateMat.width() / 2),
            Math.min(tmResult.height() - 1, pos.y + templateMat.height() / 2)
        );
        // 屏蔽已匹配到的区域
        Imgproc.rectangle(tmResult, start, end, new Scalar(0), -1);
        mmr = Core.minMaxLoc(tmResult);

        if (rect) {
            pos.x += rect.x;
            pos.y += rect.y;
            start.x += rect.x;
            start.y += rect.y;
            end.x += rect.x;
            end.y += rect.y;
        }
        let match = new Match(pos, value, factor[0], factor[1]);
        // 保存匹配点的大致范围，用于后续去重。设置enumerable为false相当于声明其为私有属性
        Object.defineProperty(match, 'matchAroundRect', { value: new Rect(start, end), writable: true, enumerable: false });
        currentMatches.push(match);
    }

    return currentMatches;
}

/**
 * 判断新检测到的点位是否与之前的某个点位重合。
 * @param {Match[]} matches
 * @param {Match} newMatch
 * @returns {boolean}
 */
function isOverlapping(matches, newMatch) {
    for (let existingMatch of matches) {
        // 也可判断两点间的距离，但是平方、开方运算不如比较范围简单高效
        if (existingMatch.matchAroundRect.contains(newMatch.point)) {
            if (newMatch.similarity > existingMatch.similarity) {
                existingMatch.point = newMatch.point;
                existingMatch.similarity = newMatch.similarity;
                existingMatch.scaleX = newMatch.scaleX;
                existingMatch.scaleY = newMatch.scaleY;
                existingMatch.matchAroundRect = newMatch.matchAroundRect;
            }
            return true;
        }
    }
    return false;
}
/*
/**
 * 根据搜图结果在原图上画框
 * @param {Match[]} matches
 * @param {*} srcMat
 * @param {*} templateMat

function showMatchRectangle(matches, srcMat, templateMat) {
    for (let match of matches) {
        let start = match.point;
        let end = new Point(
            match.point.x + templateMat.width() * match.scaleX,
            match.point.y + templateMat.height() * match.scaleY
        );
        Imgproc.rectangle(srcMat, start, end, new Scalar(0, 0, 255), 3);
    }

    const saveName = '/sdcard/Download/temp.jpg';
    let img2 = images.matToImage(srcMat);
    images.save(img2, saveName);
    app.viewFile(saveName);
    img2.recycle();
}
 */

// function main() {
//     if (!requestScreenCapture()) {
//         toastLog("请求截图失败");
//         exit();// 终止当前程序
//     } else {
//         log("请求截图成功");
//     }
//     let largeImage = captureScreen();
//     // let template = images.read('/sdcard/Download/template.jpg');
//     let template = images.read('/sdcard/Pictures/findthis.png');

//     console.log('大图尺寸:', [largeImage.getWidth(), largeImage.getHeight()]);
//     console.log('模板尺寸:', [template.getWidth(), template.getHeight()]);

//     let startTs = Date.now();
//     let result = matchTemplate(largeImage, template, {
//         threshold: 0.85,
//         region: [0, 0, device.width, device.height],
//         grayTransform: false,
//         scaleFactors: [1, 0.9, 1.1, 0.8, 1.2],
//         max: 6
//     });
//     console.log('找图耗时：', (Date.now() - startTs) / 1000);
//     console.log(result);
//     // 将结果画框展示
//     // showMatchRectangle(result, largeImage.mat, template.mat);
//     template.recycle();
//     largeImage.recycle();
// }

function thispoint() {
    let largeImage = captureScreen();
    // let template = images.read('/sdcard/Download/template.jpg');
    log(filePath);
    let template = images.read(filePath);


    let startTs = Date.now();
    let result = matchTemplate(largeImage, template, {
        threshold: 0.85,
        region: [0, 0, device.width, device.height],
        grayTransform: false,
        scaleFactors: [1, 0.9, 1.1, 0.8, 1.2],
        max: 6
    });


    // 将结果画框展示
    // showMatchRectangle(result, largeImage.mat, template.mat);
    template.recycle();
    largeImage.recycle();
    return result;

}
//全分辨率找图
function participate() {
    //className("android.widget.Image").text("aEVYAAAAAAACAI3s54qhqhUsEAAAAAElFTkSuQmCC").waitFor();
    log("正在参与……");
    var jsq2 = 0;
    while (true) {
        var ay = className("android.widget.Image").text("aEVYAAAAAAACAI3s54qhqhUsEAAAAAElFTkSuQmCC").findOne(3333)
            || className("android.widget.Image").text("osHNNdnV4HCaoA8heh3+ET4IgiAIgiAIgiAIgiAIgiAIgiAIgnv6CyT4njttsfoaAAAAAElFTkSuQmCC").findOne(3333);
        var cy = className("android.widget.Image").text("Of8AXsxn7b59CX4AAAAASUVORK5CYII=").findOne(2222)
            || className("android.widget.Image").text("3F+kBhNSy+YYaAAAAAElFTkSuQmCC").findOne(2222)
            || text("恭喜，被选中啦").findOne(2222);
        if (ay) {
            log("找到参与按钮，点击");
            try {
                real_click_with_case(ay);
            } catch (error) {
                log(error)
            }
        } else if (cy) {
            log("已参与");
            break;
        } else {
            log("未找到参与按钮，重试")
            continue
        }
        sleep(6666);
        jsq2++;
        if (jsq2 > 3) {
            break;
        }
    }


}
//初始化
if (!requestScreenCapture()) {
    toastLog("请求截图失败");
    exit();// 终止当前程序
} else {
    log("请求截图成功");
}
runtime.getImages().initOpenCvIfNeeded();



//远程
var globle = storages.create("globle");
var timerestmix = globle.get("timerestmix");
var timerestmax = globle.get("timerestmax");
var timesetmix = globle.get("timesetmix");
var timesetmax = globle.get("timesetmax");
var timemiddlemix = globle.get("timemiddlemix");
var timemiddlemax = globle.get("timemiddlemax");

// //本地
// var timerestmix = 5; timerestmax = 10;
// var timesetmix = 5; timesetmax = 10;
// var timemiddlemix = 1; timemiddlemax = 2;

var filePath = files.join(files.getSdcardPath(), 'findthis.png');
var ggopen = true;
//主程序
function maining() {
    while (true) {
        if (ggopen) {
            ggopen = false;
        } else {
            log("本次间隔：" + timeToSeconds(getRandomTime(timemiddlemix, timemiddlemax)) + "秒")
            sleep(timeToSeconds(getRandomTime(timemiddlemix, timemiddlemax)) * 1000);
        }
        var dataArr = getdata()
        if (!Array.isArray(dataArr)) {
            log(dataArr.message);
            sleep(10000);
            arr = [];
            continue;
        };
        for (m = 0; m < dataArr.length; m++) {
            if (avoidrepeat(dataArr[m])) {
                bilibilijump(dataArr[m].roomid);
                if (!liveroomyesornot()) {
                    continue;
                }
                repeat.push(dataArr[m]);
                //break;
            } else {
                continue;
            }
            var jsq3 = 0;
            while (true) {
                var a = thispoint();
                if (a.length > 0) {
                    log("找到紫包--正在参与");
                    var jsq4 = 0;
                    while (true) {
                        try {
                            real_click_with_case({ x: a[0].point.x, y: a[0].point.y });
                        } catch (error) {
                            log(a)
                        }

                        var bk = className("android.widget.Image").text("aEVYAAAAAAACAI3s54qhqhUsEAAAAAElFTkSuQmCC").findOne(1122)
                            || className("android.widget.Image").text("osHNNdnV4HCaoA8heh3+ET4IgiAIgiAIgiAIgiAIgiAIgiAIgnv6CyT4njttsfoaAAAAAElFTkSuQmCC").findOne(1122)
                            || className("android.widget.Image").text("Of8AXsxn7b59CX4AAAAASUVORK5CYII=").findOne(1122)
                            || className("android.widget.Image").text("3F+kBhNSy+YYaAAAAAElFTkSuQmCC").findOne(1122)
                            || text("恭喜，被选中啦").findOne(1122);

                        if (bk) {
                            break
                        } else {
                            jsq4++;
                            if (jsq4 > 3) {
                                break;
                            }
                        }
                    }
                    participate();
                    m = dataArr.length;
                    sleep(2222)
                    break;
                } else {
                    log("未找到紫包");
                    jsq3++;
                    if (jsq3 > 3) {
                        break;
                    }
                    continue;
                }

            }

        }
    }
}

var timeString = "00:00:00";
var timeset = "00:00:00";
var timerest = "00:00:00";
var window = floaty.window(
    <frame gravity="center">
        <vertical>
            <vertical>
                <text id="text" text="点击可调整位置" textSize="16sp" textColor="#39FF14" />
                <text id="textset" text="点击可调整位置" textSize="16sp" textColor="#FF073A" />
                <text id="textrest" text="点击可调整位置" textSize="16sp" textColor="#FF073A" />
            </vertical>
            <button id="stopBtn" text="停止脚本" w="88" h="44" />
        </vertical>
    </frame>
);

// 设置按钮点击事件
window.stopBtn.on("click", function () {
    toast("脚本已停止");
    exit();  // 退出脚本
});

window.exitOnClose();
window.text.click(() => {
    window.setAdjustEnabled(!window.isAdjustEnabled());
});
var startTime = new Date().getTime();
function pad(num) {
    return num < 10 ? '0' + num : num;
}
function getRandomTime(a, b) {
    var startSeconds = a * 60;
    var endSeconds = b * 60;

    var randomSeconds = Math.floor(Math.random() * (endSeconds - startSeconds + 1)) + startSeconds;


    var minutes = Math.floor(randomSeconds / 60);
    var seconds = randomSeconds % 60;


    return pad(minutes) + ":" + pad(seconds);
}
function timeToSeconds(time) {
    var parts = time.split(":");
    if (parts.length == 1) {
        return parseInt(parts[0]);
    } else if (parts.length == 2) {
        return parseInt(parts[0]) * 60 + parseInt(parts[1]);
    } else {
        return parseInt(parts[0]) * 3600 + parseInt(parts[1]) * 60 + parseInt(parts[2]);
    }

}
function initializeTimes() {
    timeset = getRandomTime(timesetmix, timesetmax);
    timerest = getRandomTime(timerestmix, timerestmax);
}
var resting = false;
var restStartTime = 0;
setInterval(() => {
    if (!resting) {
        if (子线程.isAlive()) {
        } else {
            子线程 = startChildThread();
        }

        var elapsedTime = (new Date().getTime() - startTime) / 1000;
        var seconds = Math.floor(elapsedTime % 60);
        var minutes = Math.floor((elapsedTime / 60) % 60);
        var hours = Math.floor((elapsedTime / 3600));

        timeString = pad(hours) + ':' + pad(minutes) + ':' + pad(seconds);
    } else {
        子线程.interrupt();
        timeString = "--:--:--";
        ggopen = true;
        timerest = timeToSeconds(timerest) - 1;
        var restSeconds = Math.floor(timerest % 60);
        var restMinutes = Math.floor((timerest / 60) % 60);
        var resthours = Math.floor((timerest / 3600));

        timerest = pad(resthours) + ':' + pad(restMinutes) + ':' + pad(restSeconds);
    }

    checkAndUpdateTimes();

    ui.run(() => {
        window.text.setText("运行时长: " + timeString);
        window.textset.setText("本次运行时间: " + timeset);
        window.textrest.setText("本次休息时间: " + timerest);
    });
}, 1000);
function checkAndUpdateTimes() {
    var timesetInSeconds = timeToSeconds(timeset);
    var timeStringInSeconds = timeToSeconds(timeString);

    if (!resting) {
        if (timeStringInSeconds >= timesetInSeconds) {
            resting = true;
            startTime = new Date().getTime();
            timeset = getRandomTime(timesetmix, timesetmax);
        }
    } else {

        if (timeToSeconds(timerest) <= 0) {
            resting = false;
            startTime = new Date().getTime();
            timerest = getRandomTime(timerestmix, timerestmax);
        }

    }
}
initializeTimes();
function startChildThread() {
    return threads.start(function () {
        maining()
    });
}
var 子线程 = startChildThread();




